﻿using System;
using System.Diagnostics;
using System.IO;

namespace Document.Library
{
    /// <summary>
    /// 视频转换工具
    /// </summary>
    public class VideoRecodeHelper
    {
        public VideoRecodeData ConvertData { get; set; }
        /// <summary>
        /// 处理工具地址
        /// </summary>
        public string FfmpegTool { get; set; }
        /// <summary>
        /// 总时长，毫秒数
        /// </summary>
        public double TotalMilliseconds { get; set; }
        /// <summary>
        /// 当前百分比率
        /// </summary>
        public double CurrentPercent { get; set; }
        /// <summary>
        /// 相应结果时，处理
        /// </summary>
        public Action<double> OnResponse { get; set; }
        /// <summary>
        /// 转换结束事件处理
        /// </summary>
        public Action<string> OnEnd { get; set; }
        /// <summary>
        /// 结束时间
        /// </summary>
        public DateTime EndTime { get; set; }

        /// <summary>
        /// 文件夹绝对路径
        /// </summary>
        public string  rootDic { get; set; }

        /// <summary>
        /// 视频时长
        /// </summary>
        string Time;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="data"></param>
        public VideoRecodeHelper(VideoRecodeData data)
        {
            this.ConvertData = data;
            this.Init();
        }

        /// <summary>
        /// 初始化处理
        /// </summary>
        private void Init()
        {
            //1.获取当前程序目录下的ffmpeg.exe文件
            rootDic = Directory.GetCurrentDirectory();
            this.FfmpegTool = rootDic + "\\ffmpeg\\ffmpeg.exe";
            if (File.Exists(FfmpegTool) == false)
                throw new Exception("ffmpeg.exe处理文件，在当前程序下没找到");
        }

        /// <summary>
        /// 指定视频分辨率，开始转换
        /// </summary>
        /// <param name="VideoSize">分辨率大小</param>
        /// <returns></returns>
        public void Start()
        {
            //执行开始时间
            DateTime startTime = DateTime.Now;
            Process p = new Process();
            p.StartInfo.FileName = this.FfmpegTool;
            p.StartInfo.Arguments = GetArgumets();
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...mencoder就是用standardOutput来捕获的)

            //外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
            p.ErrorDataReceived += new DataReceivedEventHandler(Output);

            p.Start();//启动
            p.BeginErrorReadLine();//开始异步读取
            p.WaitForExit();//阻塞登台进程技术
            p.Close();
            p.Dispose();

            if (this.ConvertData.removeSourceFile)
            {
                //删除文件
                FileHelper.FileRemove(this.ConvertData.BasePath, this.ConvertData.SourceFile);
            }
            if (this.OnEnd != null)
            {
                TimeSpan span = DateTime.Now - startTime;
                this.OnEnd(span.Hours + "小时，" + span.Minutes + "分，" + span.Seconds + "秒");
            }
        }

        /// <summary>
        /// 获取执行参数
        /// </summary>
        /// <returns></returns>
        private string GetArgumets()
        {
            //-s 320x240 指定分辨率
            //-y（覆盖输出文件，即如果1.***文件已经存在的话，不经提示就覆盖掉了）
            //-strict strictness 跟标准的严格性
            return string.Format("-i {0} -y -vcodec h264 -threads 4 -crf 25  {1}",
                rootDic + "/Files/" + this.ConvertData.BasePath + "/" + this.ConvertData.SourceFile,
                rootDic + "/Files/" + this.ConvertData.BasePath + "/" + this.ConvertData.TargetFile);

            //return string.Format("-i {0} -threads 4 -preset ultrafast -strict -2 -y -s {1} -b {2}k  {3}",
            //    rootDic+"/Files/"+ this.ConvertData.BasePath+"/" + this.ConvertData.SourceFile,
            //    this.ConvertData.VideoSize,
            //    this.ConvertData.BitRate_Video,
            //    rootDic + "/Files/" + this.ConvertData.BasePath + "/" + this.ConvertData.TargetFile);

            //return string.Format("-i {0} -y -s {1} -ar {2} -ab {3}  {4}", this.ConvertData.SourceFile,
            //    this.ConvertData.VideoSize,
            //    this.ConvertData.SamplingRate,
            //    this.ConvertData.BitRate,
            //    this.ConvertData.TargetFile);

            //return string.Format("-i {0} -y -s {1} -ar {2} -ab {3} -vol {4} {5}", this.ConvertData.SourceFile,
            //    this.ConvertData.VideoSize,
            //    this.ConvertData.SamplingRate,
            //    this.ConvertData.BitRate,
            //    this.ConvertData.Volume,
            //    this.ConvertData.TargetFile);
        }


        //输出操作处理
        private void Output(object sender, DataReceivedEventArgs e)
        {
            try
            {
                string nowtime = "";
                if (e.Data != null)
                {
                    if (e.Data.ToString().Contains("Duration"))
                    {
                        int length = e.Data.ToString().IndexOf("Duration");

                        //获取视频长度
                        Time = e.Data.ToString().Substring(e.Data.ToString().IndexOf(':') + 2, e.Data.ToString().IndexOf(':') + 1);
                    }
                    if (e.Data.ToString().Contains("frame="))
                    {
                        int timesl = 0;
                        int timesr = 0;
                        //视频总时长转毫秒
                        string[] times = Time.Split(':');
                        for (int i = 0; i < times.Length; i++)
                        {
                            switch (i)
                            {
                                case 0:
                                    timesl += int.Parse(times[i]) * 360000;
                                    break;
                                case 1:
                                    timesl += int.Parse(times[i]) * 6000;
                                    break;
                                case 2:
                                    timesl += (int.Parse(times[i].Split('.')[0]) * 100) + int.Parse(times[i].Split('.')[1]);
                                    break;
                            }
                        }

                        //当前已转码视频长度转毫秒
                        nowtime = e.Data.ToString().Split('=')[5].Substring(0, 11);
                        string[] times2 = nowtime.Split(':');
                        for (int i = 0; i < times2.Length; i++)
                        {
                            switch (i)
                            {
                                case 0:
                                    timesr += int.Parse(times2[i]) * 360000;
                                    break;
                                case 1:
                                    timesr += int.Parse(times2[i]) * 6000;
                                    break;
                                case 2:
                                    timesr += (int.Parse(times2[i].Split('.')[0]) * 100) + int.Parse(times2[i].Split('.')[1]);
                                    break;
                            }
                        }
                        float db = (float)timesr / timesl;

                        //执行委托处理
                        if (this.OnResponse != null)
                        {
                            OnResponse(Math.Round(db, 2));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 获取milliseconds
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private double GetTotalMilliseconds(string data)
        {
            if (this.TotalMilliseconds <= 0)
            {
                //string partition = @"(?<=Duration: )\d{2}:\d{2}:\d{2}.\d{2}";
                string timespan = data;// Regex.Matches(data, partition).FirstOrDefault();
                if (string.IsNullOrEmpty(timespan) == false)
                {
                    TimeSpan span;
                    if (TimeSpan.TryParse(timespan, out span))
                    {
                        this.TotalMilliseconds = span.TotalMilliseconds;
                    }
                }
            }
            return this.TotalMilliseconds;
        }

        /// <summary>
        /// 获取时间
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private double GetTime(string data)
        {
            //string partition = @"(?<=time=)\d{2}:\d{2}:\d{2}.\d{2}";
            string timespan = data;//Regex.Matches(data, partition).FirstOrDefault();
            if (string.IsNullOrEmpty(timespan) == false)
            {
                TimeSpan span;
                if (TimeSpan.TryParse(timespan, out span))
                {
                    return span.TotalMilliseconds;
                }
            }
            return 0;
        }
    }
}
